package service

import (
	"fmt"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/Kindling-project/chaos-backend/api"
	"github.com/Kindling-project/chaos-backend/internal/manager"
	"github.com/Kindling-project/chaos-backend/tools/graphql"
	"github.com/Kindling-project/chaos-backend/tools/prometheuscli"
	"github.com/gin-contrib/cache"
	"github.com/gin-contrib/cache/persistence"
	"github.com/gin-gonic/gin"
)

type DataSourceOption string

const (
	PrometheusSource DataSourceOption = "prometheus"
	SkywalkingSource DataSourceOption = "skywalking"
)

var DataSource DataSourceOption

func RegisterSceneChaos(router *gin.RouterGroup) {
	store := persistence.NewInMemoryStore(time.Minute) // 设置缓存时间为60秒
	chaosRouter := router.Group("scence")              // TODO rename scence to scene
	{
		chaosRouter.GET("/chaos/list", ListSceneChaos)
		chaosRouter.POST("/latency", cache.CachePage(store, time.Minute, QueryLatency))
		chaosRouter.POST("/throughput", cache.CachePage(store, time.Minute, QueryThroughput))
		chaosRouter.POST("/responsetimepercentile", cache.CachePage(store, time.Minute, QueryResponsetimePercentile))
		chaosRouter.GET("/config/datasource", ResetDataSource)
	}
}

func ResetDataSource(c *gin.Context) {
	dataSource := c.DefaultQuery("source", "unset")
	if dataSource == "unset" {
		api.Response(c, 200, http.StatusBadRequest, "source unset", nil)
		return
	}

	if !SetDatasource(dataSource) {
		api.Response(c, 200, http.StatusBadRequest, fmt.Sprintf("[%s] is unsupported yet, not change", dataSource), nil)
	}
}

func SetDatasource(datasource string) bool {
	switch datasource {
	case "prometheus", "skywalking":
		DataSource = DataSourceOption(datasource)
		return true
	default:
		if DataSource == "" {
			DataSource = DataSourceOption("skywalking")
		}
	}

	return false
}

func ListSceneChaos(c *gin.Context) {
	instance := c.DefaultQuery("instance", "common")
	chaos_list := manager.ListChaosTemplate(instance)
	api.ResponseOK(c, "", api.Data{
		"chaos_list": chaos_list,
	})
}

func QueryLatency(c *gin.Context) {
	serviceName := c.Query("serviceName")
	endpointName := c.Query("endpointName")
	start := c.Query("start")
	end := c.Query("end")

	var latencies map[int64]any
	var err error

	switch DataSource {
	case "skywalking":
		latencies, err = graphql.EndpointAvgLatency(serviceName, endpointName, start, end)
	case "prometheus":
		latencies, err = prometheuscli.GetRequestCallsAvgLatency(endpointName, start, end)
	}

	if latencies == nil || err != nil {
		log.Printf("failed to query AvgTime, err: %v", err)
		api.Response(c, http.StatusInternalServerError, 500, "failed to query avgTime", nil)
		return
	}

	api.ResponseOK(c, "", api.Data{
		"latencies": latencies,
	})
}

// 查询请求接口的吞吐量
func QueryThroughput(c *gin.Context) {
	serviceName := c.Query("serviceName")
	endpointName := c.Query("endpointName")
	start := c.Query("start")
	end := c.Query("end")

	var throughputs map[int64]any
	var err error

	switch DataSource {
	case "skywalking":
		throughputs, err = graphql.EndpointCps(serviceName, endpointName, start, end)
	case "prometheus":
		throughputs, err = prometheuscli.GetRequestCallsPerSecond(endpointName, start, end)
	}

	if err != nil {
		log.Printf("failed to query throughputs, err: %v", err)
		api.Response(c, http.StatusInternalServerError, 500, "failed to query throughput", nil)
		return
	}

	api.ResponseOK(c, "", api.Data{
		"throughputs": throughputs,
	})
}

func QueryResponsetimePercentile(c *gin.Context) {
	percentiles := api.PercentileParams{}
	c.BindJSON(&percentiles)

	var data = api.Data{}

	switch DataSource {
	case "skywalking":
		labeledPercentiles, err := graphql.EndpointPercentiles(percentiles.ServiceName, percentiles.EndpointName, percentiles.Start, percentiles.End)
		if err != nil {
			log.Printf("failed to query responseTimePercentiles, err: %v", err)
		}
		for label, percentData := range labeledPercentiles {
			data[graphql.PercentilesLabels[label]] = percentData
		}
	case "prometheus":
		for _, percent := range percentiles.Percent {
			responseTimePercentiles, err := prometheuscli.GetResponseTimePercentile(percent, percentiles.EndpointName, percentiles.Start, percentiles.End)
			if err != nil {
				log.Printf("failed to query responseTimePercentiles for percent [%.2f], err: %v", percent, err)
				continue
			}
			percent_str := strconv.FormatFloat(percent, 'f', 10, 64)
			data[percent_str] = responseTimePercentiles
		}
	}

	api.ResponseOK(c, "", data)
}
